﻿#region COPYRIGHT© 2005-2013 Phillip Clark. All rights reserved.

// For licensing information see License.txt (MIT style licensing).

#endregion

using System.Diagnostics.Contracts;

namespace FlitBit.Parse
{
	/// <summary>
	/// A match specification that delegates to an inner match specification.
	/// </summary>
	public class DelegatedMatch : Match
	{
		static readonly int CHashCodeSeed = typeof(DelegatedMatch).AssemblyQualifiedName.GetHashCode();

		readonly Match _match;

		/// <summary>
		/// Creates a new instance.
		/// </summary>
		/// <param name="match"></param>
		public DelegatedMatch(Match match)
			: base(match.Kind)
		{
			Contract.Requires(match != null, "match cannot be null");
			_match = match;
		}

		/// <summary>
		/// Access to the inner match rule.
		/// </summary>
		protected Match InnerMatch { get { return _match; } }

		/// <summary>
		///   Determines if the cursor position within the input is at a matching sequence.
		/// </summary>
		/// <param name="input">the input</param>
		/// <param name="cursor">the cursor</param>
		/// <returns>
		///   <em>true</em> if positioned at a matching sequence; otherwise <em>false</em>.
		/// </returns>
		public override bool At(char[] input, Cursor cursor)
		{
			return _match.At(input, cursor);
		}

		/// <summary>
		///   Determines if the cursor position within the input is at a matching sequence.
		/// </summary>
		/// <param name="input">the input</param>
		/// <param name="cursor">the cursor</param>
		/// <returns>
		///   <em>true</em> if positioned at a matching sequence; otherwise <em>false</em>.
		/// </returns>
		public override bool At(string input, Cursor cursor)
		{
			return _match.At(input, cursor);
		}

		/// <summary>
		///   Determines if the instance is equal to another.
		/// </summary>
		/// <param name="obj">the other object</param>
		/// <returns><em>true</em> if equal; otherwise <em>false</em>.</returns>
		public override bool Equals(object obj)
		{
			return obj is DelegatedMatch
				&& this.Equals((DelegatedMatch) obj);
		}

		/// <summary>
		///   Gets an array of non-variable character matches at the front. The elements
		///   in the returned array are positional such that the item at index 0 represents
		///   an exact character match for the first input character, and so on.
		/// </summary>
		/// <returns></returns>
		public override CharMatch[] GetExactCharacterMatchesOnFront()
		{
			return _match.GetExactCharacterMatchesOnFront();
		}

		/// <summary>
		///   Gets the object's hashcode.
		/// </summary>
		/// <returns></returns>
		public override int GetHashCode()
		{
			const int prime = 999067; // a random prime
			var result = CHashCodeSeed * prime;
			result ^= base.GetHashCode() * prime;
			result ^= _match.GetHashCode() * prime;
			return result;
		}

		/// <summary>
		///   Tries to match the sequence at the cursor position, advancing the cursor if successful.
		/// </summary>
		/// <param name="input">the input</param>
		/// <param name="cursor">a reference to the cursor</param>
		/// <returns>
		///   <em>true</em> if the sequence matched at the initial cursor; otherwise <em>false</em>.
		/// </returns>
		public override bool TryAt(char[] input, ref Cursor cursor)
		{
			return _match.TryAt(input, ref cursor);
		}

		/// <summary>
		///   Tries to match the sequence at the cursor position, advancing the cursor if successful.
		/// </summary>
		/// <param name="input">the input</param>
		/// <param name="cursor">a reference to the cursor</param>
		/// <returns>
		///   <em>true</em> if the sequence matched at the initial cursor; otherwise <em>false</em>.
		/// </returns>
		public override bool TryAt(string input, ref Cursor cursor)
		{
			return _match.TryAt(input, ref cursor);
		}

		/// <summary>
		/// Determines if an instance is equal to another.
		/// </summary>
		/// <param name="other">the other</param>
		/// <returns><em>true</em> if equal; otherwise <em>false</em>.</returns>
		public bool Equals(DelegatedMatch other)
		{
			return other != null
				&& Equals((Match) other)
				&& _match.Equals(other._match);
		}
	}
}